package xyz.scootaloo.kami.cloud.verticle

import io.vertx.core.eventbus.EventBus
import io.vertx.core.json.JsonObject
import io.vertx.kotlin.coroutines.CoroutineVerticle
import org.ktorm.database.Database
import xyz.scootaloo.kami.cloud.lang.*
import xyz.scootaloo.kami.cloud.lang.Constant.OK
import xyz.scootaloo.kami.cloud.model.po.*
import xyz.scootaloo.kami.cloud.service.AccountService
import xyz.scootaloo.kami.cloud.service.CacheService
import xyz.scootaloo.kami.cloud.service.ServiceLifeCycle
import xyz.scootaloo.kami.cloud.service.TokenService

/**
 * 状态管理: 缓存服务, 定时任务服务, 用户状态, 上传任务/状态, 下载令牌映射
 * 服务管理: 加解密, 客户端身份认证
 *
 * @author flutterdash@qq.com
 * @since 2022/4/10 14:07
 */
@EventLoop(Constant.CTX_STATE)
object StateCenterVerticle : CoroutineVerticle() {

    private val log by lazy { getLogger("state-center") }

    private lateinit var eb: EventBus

    override suspend fun start() {
        eb = vertx.eventBus()
        registerEventbusConsumers()
        ServiceLifeCycle.publishAppStartedEvent()
        prepareGlobalDatabaseRef()
    }

    override suspend fun stop() {
    }

    fun deploymentId(): String {
        return deploymentID
    }

    private fun registerEventbusConsumers() {
        registerCacheServiceConsumers()
        registerAccountServiceConsumers()
        registerTokenServiceConsumers()
    }

    private fun prepareGlobalDatabaseRef() {
        vertx.runOnContext {
            val fileConf = Global.APP_FILE_CONF
            val ref = Database.connect(
                driver = "org.sqlite.JDBC",
                url = "jdbc:sqlite:${fileConf.dbFile}"
            )
            Global.DATABASE_REF = ref
            ServiceLifeCycle.publishDatabaseAvailableEvent()
        }
    }

    private val cacheService = CacheService().internal()

    private fun registerCacheServiceConsumers() {
        eb.consumer<String>(Constant.EB_CACHE_GET) { request ->
            val cacheKey = request.body()
            val value = cacheService.get<String>(cacheKey)
            request.reply(value)
        }

        eb.consumer<JsonObject>(Constant.EB_CACHE_PUT) { request ->
            val cacheEntry = deserializer<CacheEntry>(request.body())
            cacheService.put(cacheEntry.key, cacheEntry.value)
            request.reply(OK)
        }

        eb.consumer<String>(Constant.EB_CACHE_DEL) { request ->
            val cacheKey = request.body()
            cacheService.delete(cacheKey)
            request.reply(OK)
        }

        eb.consumer<JsonObject>(Constant.EB_CACHE_UpEx) { request ->
            val expiry = deserializer<CacheUpdateExpiry>(request.body())
            cacheService.updateExpiryTime(expiry.key, expiry.newExpiryTime)
            request.reply(OK)
        }
    }

    private val accountService = AccountService().internal()

    private fun registerAccountServiceConsumers() {
        eb.consumer<JsonObject>(Constant.EB_ACCOUNT_REGISTER) { request ->
            val process = deserializer<AccountFormBlock>(request.body())
            accountService.register(process.ipAddress, process.form)
                .onSuccess { request.reply(serializer(it)) }
                .onFailure { err ->
                    log.error("注册调用出错", err)
                    request.reply(serializer(ServiceResult.error<String>()))
                }
        }

        eb.consumer<JsonObject>(Constant.EB_ACCOUNT_LOGIN) { request ->
            val process = deserializer<AccountFormBlock>(request.body())
            accountService.login(process.ipAddress, process.form)
                .onSuccess { request.reply(serializer(it)) }
                .onFailure { err ->
                    log.error("登录调用出错", err)
                    request.reply(serializer(ServiceResult.error<String>()))
                }
        }

        eb.consumer<JsonObject>(Constant.EB_ACCOUNT_P_LOGIN) { request ->
            val process = deserializer<AccountPlaintextFormBlock>(request.body())
            accountService.login(process.ipAddress, process.username, process.password)
                .onSuccess { request.reply(serializer(it)) }
                .onFailure { err ->
                    log.error("明文登录调用出错", err)
                    request.reply(serializer(ServiceResult.error<String>()))
                }
        }

        eb.consumer<String>(Constant.EB_ACCOUNT_LOGOUT) { request ->
            request.reply(OK)
        }

        eb.consumer<String>(Constant.EB_ACCOUNT_FD_USER) { request ->
            val username = request.body()
            accountService.findUserByName(username)
                .onSuccess {
                    if (it == null)
                        request.reply(null)
                    else
                        request.reply(serializer(it))
                }
                .onFailure { err ->
                    log.error("查找用户调用出错", err)
                    request.reply(err)
                }
        }
    }

    private val tokenService = TokenService().internal()

    private fun registerTokenServiceConsumers() {
        eb.consumer<JsonObject>(Constant.EB_TOKEN_GEN) { request ->
            val process = deserializer<TokenGenBlock>(request.body())
            val token = tokenService.generateToken(process.ipAddress, process.expiryTime)
            request.reply(serializer(token))
        }

        eb.consumer<JsonObject>(Constant.EB_TOKEN_DEC) { request ->
            val process = deserializer<TokenContentDecodeBlock>(request.body())
            val rsl = tokenService.decodeContent(process.ipAddress, process.clientId, process.base64encoded)
            request.reply(serializer(rsl))
        }
    }
}